/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.idea.utils.sfo;


import designersfo.Root;
import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.util.Collection;
import javax.swing.JScrollPane;
import javax.xml.bind.JAXBException;
import org.idea.utils.sfo.designer.DesignerRowChildren;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.ExplorerUtils;
import org.openide.explorer.view.BeanTreeView;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle.Messages;
import org.openide.util.Utilities;
import org.openide.windows.TopComponent;


/**
 * Top component which displays the ExplorerManager tree (element nodes) and the
 * Canvas Panel that contains the canvas with the graphical representation of
 * the elements in the SFO.
 */
@ConvertAsProperties(
dtd = "-//org.idea.utils.sfo//SFOModuleView//EN" ,
autostore = false )
@TopComponent.Description(
preferredID = "SFOModuleViewTopComponent" ,
//iconBase="SET/PATH/TO/ICON/HERE",
persistenceType = TopComponent.PERSISTENCE_ALWAYS )
@TopComponent.Registration( position = 3, mode = "editor" , openAtStartup = false )
@ActionID( category = "Window" , id = "org.idea.utils.sfo.SFOModuleViewTopComponent" )
@ActionReferences({
        @ActionReference( path = "Menu/Window" , position = 833  ),
        @ActionReference( path = "Menu/File/Open" , position = 1700 )
})
@TopComponent.OpenActionRegistration(
displayName = "#CTL_SFOModuleViewAction" ,
preferredID = "SFOModuleViewTopComponent" )
@Messages(
{
    "CTL_SFOModuleViewAction=SFOModuleView" ,
    "CTL_SFOModuleViewTopComponent=SFO Tree View Window" ,
    "HINT_SFOModuleViewTopComponent=This is a SFO Tree View window"
} )
public final class TreeTopComponent extends TopComponent implements ExplorerManager.Provider , LookupListener
{

    /**
     * Panel wrapping the canvas.
     */
    private CanvasPanel cpanel;
    /**
     *
     */
    private transient ExplorerManager exploMan = new ExplorerManager();
    /**
     *
     */
    private Lookup.Result<Node> nodeResultListener;
    /**
     * The SFODocManager object manages reading / writing to the SFO XML
     * Document.
     */
    private SFODocManager sfoManager;
    /**
     * Displays the nodes in the SFO tree.
     */
    private JScrollPane sfoTreeView;
    /**
     * When true be verbose about what's going on.
     */
    private boolean verbose;


    /**
     *
     */
    public TreeTopComponent()
    {
        // set the layout manager for this windonw
        this.setLayout( new BorderLayout() );

        this.setName( Bundle.CTL_SFOModuleViewTopComponent() );
        this.setToolTipText( Bundle.HINT_SFOModuleViewTopComponent() );

        /**
         * ER add To allow printing
         */
        putClientProperty( "print.printable" , Boolean.TRUE );
        putClientProperty( "print.name" , "Ed's Designer SFO Elements" );

        this.verbose = true;

        // the bean tree view will display the row and column nodes contained in
        // the SFO's XML DOcument
        this.sfoTreeView = new BeanTreeView();

        // The Explorer Manager tree handles the nodes created from the SFO
        // elements, it displays them in a tree structure and passes them to the
        // properties tab when clicked on.
        exploMan = new ExplorerManager();
        this.associateLookup( ExplorerUtils.createLookup( exploMan , getActionMap() ) );

        // Adding a property change listener to the Explorer Manager tree so we
        // can decide which actions to perform when the users click on it.
        this.exploMan.addPropertyChangeListener( new TreeChangeListener( this.verbose ) );

        //
        this.cpanel = new CanvasPanel( this , verbose );
        this.add( cpanel , BorderLayout.EAST );

        //
        this.add( sfoTreeView , java.awt.BorderLayout.CENTER );
    }


    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents()
    {

        sfoPane = new BeanTreeView();

        this.setLayout(new java.awt.BorderLayout());
        // WEST
        // add(sfoPane, java.awt.BorderLayout.CENTER);
        this.add(sfoPane, java.awt.BorderLayout.WEST);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane sfoPane;
    // End of variables declaration//GEN-END:variables


    /**
     *
     */
    @Override
    public void componentOpened()
    {
        // setup a result listener for nodes.
        this.nodeResultListener = Utilities.actionsGlobalContext().lookupResult( Node.class );
        this.nodeResultListener.addLookupListener( this );
    }


    /**
     *
     */
    @Override
    public void componentClosed()
    {
        // TODO add custom code on component closing
        this.nodeResultListener.removeLookupListener( this );
    }


    /**
     *
     * @param sfoDocManager
     */
    public void displaySFO( SFODocManager sfoDocManager )
    {
        this.sfoManager = sfoDocManager;
        this.displayTree();
    }


    /**
     * Display the SFO's XML Doc tree in its component.
     */
    private void displayTree()
    {
        // 1. avoid basic problems by checking for nulls
        if ( this.sfoManager.getDocRoot() != null )
        {
            // 2. parse all the elements in the document root and build the row and
            //    column element trees.
            DesignerRowChildren drc = new DesignerRowChildren( this.sfoManager.getDocRoot().getConsVOrConsOrEmptyV() );

            // 3. assign the element trees to the Explorer Manager.
            exploMan.setRootContext( new AbstractNode( drc ) );
            exploMan.getRootContext().setDisplayName( "Designer SFO" );

            // 4. pass all the elements in the document root to the canvas so it can
            //    display them as well.
            this.cpanel.clearGraphics();
            this.cpanel.setGrahpicObjects( drc );
        } else
        {
            exploMan.setRootContext( Node.EMPTY );
            exploMan.getRootContext().setDisplayName( "No Designer SFO to display" );
        }
    }


    /**
     *
     * @return a reference to the SFO's XML Document Root
     */
    public Root getDocRoot()
    {
        return this.sfoManager.getDocRoot();
    }


    /**
     *
     * @return
     */
    @Override
    public ExplorerManager getExplorerManager()
    {
        return exploMan;
    }


    /**
     * Gets the list of selected nodes in the tree list.
     *
     * @return
     */
    public Node[] getNodes()
    {
        Node[] nodes = this.exploMan.getSelectedNodes();

        return nodes;
    }


    /**
     *
     * @param p
     */
    void readProperties( java.util.Properties p )
    {
        String version = p.getProperty( "version" );
        // TODO read your settings according to their version
    }


    /**
     *
     * @param le
     */
    @Override
    public void resultChanged( LookupEvent le )
    {
        Collection<? extends Node> allNodes = nodeResultListener.allInstances();

        for ( Node n : allNodes )
        {
            System.out.println( "TreeTopComponent : " + n );
        }
    }


    /**
     *
     * @throws JAXBException
     */
    public void saveSFO() throws JAXBException
    {
        this.sfoManager.saveSFO();
    }


    /**
     *
     * @param nodes
     * @throws PropertyVetoException
     */
    public void setSelectedTreeNodes( Node[] nodes ) throws PropertyVetoException
    {
        this.exploMan.setSelectedNodes( nodes );
    }


    /**
     *
     * @param p
     */
    void writeProperties( java.util.Properties p )
    {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty( "version" , "1.0" );
        // TODO store your settings
    }


    /**
     * TreeChangeListener listens to property changes that take place on the
     * ExplorerManager tree.
     *
     * Its purpose is to allow the canvas to highlight the element(s) the user
     * has selected in the ExplorerManager tree.
     */
    private class TreeChangeListener implements PropertyChangeListener
    {

        /**
         * When true, be verbose.
         */
        private boolean verbose;


        /**
         *
         * @param verbose
         */
        public TreeChangeListener( boolean verbose )
        {
            this.verbose = verbose;
        }


        /**
         * Set of currently selected nodes.
         *
         * This set will only need to perform insert and remove operations, it
         * isn't required to keep the items in order so a java.util.HashSet is
         * the best choice.
         */
        //private HashSet<Node> currentNodes = new HashSet<Node>();
        /**
         *
         * @param evt
         */
        @Override
        public void propertyChange( PropertyChangeEvent evt )
        {
            if ( ExplorerManager.PROP_SELECTED_NODES.equals( evt.getPropertyName() ) )
            {
                if ( verbose )
                {
                    System.out.println( "TreeChangeListener " + evt );
                }

                Node[] selectedNodes = exploMan.getSelectedNodes();
                // 
                cpanel.setSelectedNodes( selectedNodes );

                //
                if ( verbose )
                {
                    for ( int i = 0; i < selectedNodes.length; i++ )
                    {
                        System.out.println( "Selected Node: " + selectedNodes[i] );
                    }
                }
                //updateContentNodes( exploMan.getSelectedNodes() );
            }
        }
        // USELESS SINCE THE ExplorerManager TAKES CARE OF ALL THIS FOR US.

        /**
         * Update the nodes in the org.openide.util.lookup.InstanceContent.
         *
         * We're using an InstanceContent to communicate the nodes currently
         * selected in the ExplorerManager tree.
         *
         * This means that we're responsible for keeping track of which nodes
         * are currently selected and which are not (anymore).
         *
         * @param newNodes
         */
//        private void updateContentNodes( Node[] newNodes )
//        {
//            // put the array list of new nodes into a new set.
//            HashSet<Node> newNodeSet = new HashSet<Node>( newNodes.length );
//            for ( int i = 0; i < newNodes.length; i++ )
//            {
//                System.out.println( "Selected Node: " + newNodes[i] );
//                newNodeSet.add( newNodes[i] );
//            }
//
//            /* Remove all the newly selected nodes from the current nodes list,
//             * this will leave only the "un-selected" nodes in currentNodes and
//             * we need to remove all of these from InstanceContent
//             */
//            this.currentNodes.removeAll( newNodeSet );
//
//            for ( Node old : currentNodes )
//            {
//                content.remove( old );
//            }
//
//            /* Add all the newly selected nodes to the InstanceContent and then
//             * to the currentNodes set to keep it updated.
//             */
//            for ( Node newNode : newNodeSet )
//            {
////                content.add( newNode );
//            }
//
//            this.currentNodes.addAll( newNodeSet );
//        }
    }

}
